home *** CD-ROM | disk | FTP | other *** search
- {
- GPC demo program for the portable use of `absolute' declarations and
- how to take care of type sizes and endianness in portable programs.
-
- Copyright (C) 1999-2001 Free Software Foundation, Inc.
-
- Author: Frank Heckenbach <frank@pascal.gnu.de>
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation, version 2.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-
- As a special exception, if you incorporate even large parts of the
- code of this demo program into another program with substantially
- different functionality, this does not cause the other program to
- be covered by the GNU General Public License. This exception does
- not however invalidate any other reasons why it might be covered
- by the GNU General Public License.
- }
-
- program AbsoluteDemo;
-
- { This is an actual example taken from GPC's CRT unit. Under normal
- circumstances, tricks like the following are *not* necessary.
- They're only meant for special situations that can't be solved
- otherwise.
-
- The situation here is the following: The writers of BP's CRT unit
- had the "brilliant" idea to stuff two values into one variable
- (the minimum x and y coordinates of the current window into
- WindMin and similarly the maximum coordinates into WindMax).
- The x coordinates reside in the lower 8 bits, and the y
- coordinates in the higher 8 bits of the `Word' variables which are
- 16 bit in BP. (They apparently thought this was necessary for
- their assembler code to be more efficient which is actually not
- true, but that's another story...)
-
- Their recommended way to access the coordinates is to use bit
- manipulation like `shl', `shr', `and' and `or' (or, mostly
- equivalently, `*', `div' and `mod' by powers of 2). But, of
- course, that's not very comfortable for a language like Pascal.
-
- So we want to make the access easier by using fields of a record,
- without losing compatibility to the thoughtless BP interface.
-
- The way to do it is an `absolute' declaration to create record
- aliases for the `Word' variables. `absolute' declarations are
- supported by the GNU Pascal compiler, so far so good. However, in
- order to remain portable, there are two things to take care of:
- type sizes and endianness.
-
- Type sizes: as always when programming portably, one must not
- assume anything about type sizes except when explicitly requested.
- In particular, we must not assume that a `Word' is 16 bits (and in
- fact, it's usually bigger in GPC). Therefore, there might be
- unused bits in the `Word' variables which we cover with (dummy)
- `Fill' fields in the records. For the (interesting) `X' and `Y'
- fields, we want exactly 8 bits, so we use `Word (8)' (and not
- `Byte', which is usually 8 bits, but not guaranteed to be). To
- compute the size of the `Fill' field in bits, we can then simply
- subtract 16 (the size of the `X' and `Y' fields) from the size of
- `Word' in bits which the `BitSizeOf' function tells us. But
- because we're really paranoid ;-), we add a (compile time) check
- to ensure that the size of our record is really the same as that
- of the `Word' variables. Compile time assertions are not directly
- supported by the compiler, but can be emulated with a little
- trick, see below.
-
- Endianness: on a little-endian system (e.g. x86, Alpha), the lower
- valued parts of an integer variable come first in memory, but on a
- big-endian system (e.g. m68k, Sparc), the higher valued parts come
- first. We must take this into account in the order of the fields
- in our record. GPC gives us the define `__BYTES_LITTLE_ENDIAN__'
- or `__BYTES_BIG_ENDIAN__' in order to distinguish little- and
- big-endian systems.
-
- And last, but not least, of course, we must not forget to use a
- `packed' record, so the fields are really packed end to end. }
-
- { First of all, these are the `Word' variables we want to alias. }
- var
- WindMin : Word;
- WindMax : Word;
-
- { Now our record type, taking into account type sizes and endianness. }
- type
- TWindowXY = packed record
- {$ifdef __BYTES_BIG_ENDIAN__}
- Fill : Integer (BitSizeOf (Word) - 16);
- Y, X : Word (8)
- {$else}
- X, Y : Word (8);
- Fill : Integer (BitSizeOf (Word) - 16)
- {$endif}
- end;
-
- { Make sure TWindowXY really has the same size as WindMin and
- WindMax. If not, compilation will abort here with `division by
- zero'. Otherwise, the value of the constant will always be 1, and
- is of no further interest. }
- const
- AssertTWindowXYSize = 1 / Ord ((SizeOf (TWindowXY) = SizeOf (WindMin)) and
- (SizeOf (TWindowXY) = SizeOf (WindMax)));
-
- { And now the aliased record variables via `absolute' declarations. }
- var
- WindowMin : TWindowXY absolute WindMin;
- WindowMax : TWindowXY absolute WindMax;
-
- begin
- Writeln ('Setting the minimum coordinates (2, 4) the "dirty" way.');
- WindMin := 2 + $100 * 4;
- Writeln ('Reading them back the easy way: (', WindowMin.X, ', ', WindowMin.Y, ').');
- Writeln;
- Writeln ('And vice versa...');
- Writeln ('Setting the maximum coordinates to (42, 24) the easy way.');
- WindowMax.X := 42;
- WindowMax.Y := 24;
- Writeln ('Reading them back the "dirty" way: (', WindMax mod $100, ', ', WindMax div $100, ').')
- end.
-